#include "moz_xul_reference.hpp"
#include <sstream>
#include <fstream>
#include <algorithm>
#include <boost/algorithm/string.hpp>

const char moz_xul_reference::DELIMITER = ',';
const char moz_xul_reference::COMMENT = '#';

bool moz_xul_reference::parse(const char *filename)
{
	std::string line;
	unsigned int num(0), semaphore(0);
	bool status(false);

	std::pair<std::map< unsigned int, std::string >::iterator, bool> str_res;
	std::pair<std::map< unsigned int, bool >::iterator, bool> sem_res;


	std::ifstream input_file(filename);
	if (input_file.is_open())
	{
		while ( input_file.good() )
		{
			std::getline (input_file,line);

			line = boost::trim_left_copy(line);
			if(line[0] == COMMENT) continue;

			std::string directive = line.substr(0, line.find_first_of(DELIMITER));
			//directive.erase(std::remove_if(directive.begin(), directive.end(), isspace), directive.end());
			boost::trim(directive);

			std::stringstream id(directive);
			id >> num; // line id

			if((status = (id.rdbuf()->in_avail() == 0))) // in case it is a number
			{				
//				std::cout << "command_id = " << num << std::endl;

				line = line.substr(line.find_first_of(DELIMITER)+1, line.length());
				directive = line.substr(0, line.find_first_of(DELIMITER)); // extract semaphore value
				//directive.erase(std::remove_if(directive.begin(), directive.end(), isspace), directive.end());
				boost::trim(directive);
				
				std::stringstream id_sem(directive);
				id_sem >> semaphore;
				if( id_sem.rdbuf()->in_avail() != 0 )  // if semaphore is not a number, it is supposed to be null
					semaphore =0;

				sem_res = _semaphore_map.insert(std::make_pair(num, semaphore ? true: false));
//				std::cout << "red light = " << semaphore << std::endl;

				line = line.substr(line.find_first_of(DELIMITER)+1, line.length()); // extract remaining string, as xul command or value
				boost::trim(line);
				str_res = _xul_reference_map.insert(std::make_pair(num, line));																					
//				std::cout << "command = " << line << std::endl;
			}
			else break;			
		}
	}

	input_file.close();

	return status;
}


bool moz_xul_reference::init_from(std::string const& _filename)
{
	moz_xul_iterator::_reference_iter = _xul_reference_map.end();

	if(parse(_filename.c_str()))
		if(!_xul_reference_map.empty())
	{
		moz_xul_iterator::_reference_iter = _xul_reference_map.begin();
		return true;
	}

	return  false;
}

bool moz_xul_reference::empty()
{
	return _xul_reference_map.empty();
}


bool moz_xul_reference::get_semaphore(unsigned int _id) const
{
	std::map <unsigned int, bool>::const_iterator iterator = _semaphore_map.find(_id);
	if(iterator != _semaphore_map.end()) 
		return iterator->second;

	return true;
}

std::string const moz_xul_reference::get_reference(unsigned int _id) const
{
	std::map <unsigned int, std::string >::const_iterator iterator = _xul_reference_map.find(_id);
	if(iterator != _xul_reference_map.end()) return iterator->second;

	return "";
}


std::ostream& operator << (std::ostream& ost, moz_xul_reference const& c)
{
	std::map < unsigned int, std::string >::const_iterator j = c._xul_reference_map.begin();
	std::map < unsigned int, std::string >::const_iterator k = c._xul_reference_map.end();

	for(; j != k; j++)
	{
		ost << j->first << ", " << c.get_semaphore(j->first) << ", " << j->second << std::endl;
	}

	return ost;
}


int moz_xul_reference::get_id() const
{
	if(moz_xul_iterator::_reference_iter != _xul_reference_map.end())
		return moz_xul_iterator::_reference_iter->first;

	return -1;
}

moz_xul_reference const& moz_xul_reference::operator++() const
{
	if(moz_xul_iterator::_reference_iter != _xul_reference_map.end())
	{
		moz_xul_iterator::_reference_iter++;
	}

	return *this;
}


moz_xul_reference::moz_xul_reference(std::string const& _filename)
{
	init_from(_filename);
}

moz_xul_value::moz_xul_value(std::string const& _filename)
{
	init_from(_filename);
}

#include "moz_token_callback.hpp"

std::string const moz_xul_value::get_reference(unsigned int _id) const
{
	std::map <unsigned int, std::string >::const_iterator iterator = _xul_reference_map.find(_id);
	if(iterator != _xul_reference_map.end()) 
	{
		std::map <unsigned int, bool >::const_iterator sem_iterator = _semaphore_map.find(_id);
		if(sem_iterator == _semaphore_map.end()) return "";

		if(sem_iterator != _semaphore_map.end() && !(sem_iterator->second)) // clear text
			return iterator->second; 
		else
			return moz_token_interface::decrypt_from(_id, encrypting(_id), iterator->second, _indices); // action must be taken to encrypt or decrypt value
	}

	return "";
}

unsigned short moz_xul_value::get_index(unsigned short j) 
{
	return _indices[j];
}

int moz_xul_value::get_id() const
{
	return -1;
}

moz_xul_value const& moz_xul_value::operator++() const
{
  return *this;
}

bool moz_xul_value::init_from(std::string const& _filename)
{
	return (parse(_filename.c_str()) && !_xul_reference_map.empty());
}

bool moz_xul_value::parse(const char *filename)
{
	std::string line;
	unsigned int num(0);
	bool semaphore(false);
	bool status(false);

	std::pair<std::map< unsigned int, std::string >::iterator, bool> str_res;
	std::pair<std::map< unsigned int, bool >::iterator, bool> sem_res;


	std::ifstream input_file(filename);
	if (input_file.is_open())
	{
		while ( input_file.good() )
		{
			std::getline (input_file,line);
			line = boost::trim_left_copy(line);
			if(line[0] == COMMENT) continue;

			std::string directive = line.substr(0, line.find_first_of(DELIMITER));
			//directive.erase(std::remove_if(directive.begin(), directive.end(), isspace), directive.end());
			boost::trim(directive);
			std::stringstream id(directive);
			id >> num; // line id

			if((status = (id.rdbuf()->in_avail() == 0))) // in case it is a number
			{				
				line = line.substr(line.find_first_of(DELIMITER)+1, line.length());
				directive = line.substr(0, line.find_first_of(DELIMITER)); // extract semaphore value
				//directive.erase(std::remove_if(directive.begin(), directive.end(), isspace), directive.end());
				boost::trim(directive);

				std::stringstream id_sem(directive);
				id_sem >> semaphore;
				if( id_sem.rdbuf()->in_avail() != 0 )  // if semaphore is not a number, value is supposed clear text
					semaphore =0;
				
				sem_res = _semaphore_map.insert(std::make_pair(num, semaphore));

				line = line.substr(line.find_first_of(DELIMITER)+1, line.length()); // extract remaining string, as xul command or value
				directive = line.substr(0, line.find_first_of(DELIMITER)); // extract semaphore value
				boost::trim(directive);

				if(semaphore) // as long as it is an encrypted value
				{
					std::stringstream id_tk(directive);
					id_tk >> semaphore;
					if( id_tk.rdbuf()->in_avail() != 0 )  
						semaphore =0; // decrypt by default

					sem_res = _encrypt_map.insert(std::make_pair(num, semaphore)); // shall we encrypt or decrypt?
				}

				line = line.substr(line.find_first_of(DELIMITER)+1, line.length()); // extract remaining string, as xul value
				boost::trim(line);

				str_res = _xul_reference_map.insert(std::make_pair(num, line));																					
			}
			else break;			
		}
	}

	input_file.close();

	return status;
}

bool moz_xul_value::encrypting(unsigned int _id) const
{
	std::map <unsigned int, bool>::const_iterator iterator = _encrypt_map.find(_id);
	if(iterator != _encrypt_map.end()) return iterator->second;

	return false;
}

bool moz_xul_value::decrypting(unsigned int _id) const
{
	return !encrypting(_id);
}


std::map< unsigned int, std::string >::iterator moz_xul_iterator::_reference_iter;

unsigned short moz_xul_value::_indices[256];
